package io.noties.markwon.app.sample;


import com.noties.markwon.annotation.NonNull;
import com.noties.markwon.annotation.Nullable;
import com.noties.markwon.utils.LogUtils;

import io.noties.markwon.sample.annotations.MarkwonArtifact;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import ohos.utils.Pair;
import ohos.utils.net.Uri;

/**
 * @author: yangrui
 * @function:
 * @date: 2021/3/23
 */
public abstract class Deeplink {
    private static final String TAG = "Deeplink";
    private static final String DEEPLINK_SCHEME = "markwon";

    private Deeplink() {
    }

    static final class Sample extends Deeplink {
        @NonNull
        private final String id;

        Sample(String id) {
            this.id = id;
        }

        public String getId() {
            return id;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Sample sample = (Sample) o;
            return Objects.equals(id, sample.id);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id);
        }

        @Override
        public String toString() {
            return "Sample{" +
                    "id='" + id + '\'' +
                    '}';
        }


    }

    static final class Search extends Deeplink {
        @NonNull
        private final SampleSearch search;

        @NonNull
        public final SampleSearch getSearch() {
            return this.search;
        }

        Search(@NonNull SampleSearch search) {
            this.search = search;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Search search1 = (Search) o;
            return Objects.equals(search, search1.search);
        }

        @Override
        public int hashCode() {
            return Objects.hash(search);
        }

        @Override
        public String toString() {
            return "Search{" +
                    "search=" + search +
                    '}';
        }
    }

    @Nullable
    public static final Deeplink parse(@Nullable Uri data) {
        if (data == null) {
            return null;
        }
        LogUtils.i(TAG, data.toString() + "");


        String dataScheme = data.getScheme();
        Deeplink deeplink;
        if (dataScheme != null) {
            switch (dataScheme) {
                // https deeplink, `https://noties.io/Markwon/sample`
                // https://noties.io/Markwon/app/sample/ID
                // https://noties.io/Markwon/app/search?a=core
                case "https":
                    List<String> segments = data.getDecodedPathList();
                    if (segments.size() == 3 && "Markwon".equals(segments.get(0))&& "app".equals(segments.get(1))) {
                        switch (segments.get(2)) {
                            case "sample":
                                deeplink = parseSample(data.getLastPath());
                                return deeplink;
                            case "search":
                                deeplink = parseSearch(data.getDecodedQuery());
                                return deeplink;
                            default:
                                break;
                        }
                    }
                    break;
                case DEEPLINK_SCHEME:
                    String host = data.getDecodedHost();
                    switch (host) {
                        case "sample":
                            deeplink = parseSample(data.getLastPath());
                            return deeplink;

                        case "search":
                            deeplink = parseSearch(data.getDecodedQuery());
                            return deeplink;
                        default:
                    }
                    break;
                default:
            }
        }

        deeplink = null;
        return deeplink;
    }


    private static Deeplink.Sample parseSample(String id) {
        return id == null ? null : new Deeplink.Sample(id);
    }

    private static Deeplink.Search parseSearch(String query) {
        LogUtils.i(TAG, "query: '" + query + '\'');
        if (query != null) {
            int index = query.indexOf("?");
            String tmpQuery = query;
            if (index > -1) {
                tmpQuery = query.substring(index + 1);
            }
            String[] splits = tmpQuery.split("&");
            Map<String, String> params = Arrays.stream(splits)
                    .map(it -> {
                        String[] tempsplits = it.split("=");
                        String k = tempsplits[0];
                        String v = tempsplits[1];
                        Pair<String, String> pair = new Pair<>(k, v);
                        return pair;
                    })
                    .collect(Collectors.toMap(pair -> pair.f, pair -> pair.s));
            if (params == null) {
                return null;
            }
            LogUtils.i(TAG, "params: " + params);
            String artifact = params.get("a");
            String tag = params.get("t");
            String search = params.get("q");
            LogUtils.i(TAG, "artifact: '" + artifact + "', tag: '" + tag + "', search: '" + search + '\'');

            SampleSearch sampleSearch;
            if (artifact != null) {
                MarkwonArtifact encodedArtifact = Arrays.stream(MarkwonArtifact.values())
                        .filter(it -> it.artifactName().equals(artifact))
                        .findFirst()
                        .orElse(null);
                if (encodedArtifact != null) {
                    sampleSearch = new SampleSearch.Artifact(search, encodedArtifact);
                } else {
                    sampleSearch = null;
                }
            } else if (tag != null) {
                sampleSearch = new SampleSearch.Tag(search, tag);
            } else if (search != null) {
                sampleSearch = new SampleSearch.All(search);
            } else {
                sampleSearch = null;
            }

            if (sampleSearch == null) {
                return null;
            }
            return new Search(sampleSearch);
        }
        return null;
    }

}
